#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Author          : ricsy
@File            : check_env.py.py
@Create Time     : 2025/6/16 04:14
@Last Modified   :
@Description     : 环境依赖检查工具 ，用于验证构建所需的所有依赖是否已正确安装
"""
import subprocess
import sys
from pathlib import Path
from typing import List, Literal, TypedDict

from src.settings import logger, project_root


PlatformType = Literal["windows", "mac", "linux"]
PLATFORM_MAP: dict[str, PlatformType] = {
    "win32": "windows",
    "darwin": "mac",
    "linux": "linux",
    "linux2": "linux",
}


class DependencyConfig(TypedDict):
    test_cmd: str
    cmd_args: str
    install_guide: str
    local_path: str
    common_paths: dict[PlatformType, List[str]]  # 精确到平台类型


# 依赖配置常量
DEPENDENCIES: dict[str, DependencyConfig] = {
    "node": DependencyConfig(
        test_cmd="node",
        cmd_args="--version",
        install_guide="从 https://nodejs.org/ 安装 Node.js",
        local_path="",  # 没有本地路径时给空字符串
        common_paths={},  # 没有公共路径时给空字典
    ),
    "pnpm": DependencyConfig(
        test_cmd="pnpm",
        cmd_args="--version",
        install_guide="npm install -g pnpm",
        local_path="",
        common_paths={},
    ),
    "sass": DependencyConfig(
        test_cmd="sass",
        cmd_args="--version",
        install_guide="pnpm add -D sass@1.89.2",
        local_path="node_modules/.bin/sass",
        common_paths={
            "windows": [
                "C:/dart-sass/sass.bat",
                "C:/Program Files/dart-sass/sass.bat",
            ],
            "linux": [
                "/usr/local/bin/sass",
                "/opt/dart-sass/sass",
            ],
            "mac": [
                "/usr/local/bin/sass",
                "/opt/dart-sass/sass",
            ],
        },
    ),
    "webpack": DependencyConfig(
        test_cmd="webpack",
        cmd_args="--version",
        install_guide="pnpm add -D webpack webpack-cli",
        local_path="node_modules/.bin/webpack",
        common_paths={},
    ),
}


class EnvironmentChecker:
    """环境检查工具类"""

    @staticmethod
    def _test_command(bin_path: str, cmd_args: str) -> str | None:
        """测试单个依赖是否可用"""
        try:
            subprocess.run(
                [bin_path, cmd_args],
                check=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                text=True,
                shell=True,
                encoding="utf-8",
            )
            return bin_path
        except (subprocess.CalledProcessError, FileNotFoundError):
            return None

    def get_executable_path(self, name: str) -> str | None:
        """检查依赖安装情况（按优先级）"""
        config = DEPENDENCIES[name]
        cmd_args = config["cmd_args"]
        sys_platform = PLATFORM_MAP[sys.platform]

        # 1. 首先尝试全局命令
        bin_path = self._test_command(config["test_cmd"], cmd_args)

        # 2. 检查项目本地安装
        if (not bin_path or sys_platform == "windows") and "local_path" in config:
            local_path = project_root / config["local_path"]
            if sys_platform == "windows":
                local_path = Path(f"{local_path}.CMD")
            if local_path.exists():
                bin_path = self._test_command(str(local_path), cmd_args)

        # 3. 检查常见安装路径
        if not bin_path and "common_paths" in config:
            platform_paths = config["common_paths"].get(sys_platform, [])
            for path in platform_paths:
                if Path(path).exists():
                    bin_path = self._test_command(path, cmd_args)

        return bin_path

    def check_environment(self) -> bool:
        """执行完整环境检查"""
        missing_deps = []

        # 检查依赖
        for name in DEPENDENCIES:
            if not self.get_executable_path(name):
                missing_deps.append(name)
            else:
                logger.info(f"{name} 已安装", 2)

        # 输出结果
        if missing_deps:
            logger.error("❌ 缺少以下依赖:")
            for name in missing_deps:
                logger.error(f"- {name}: {DEPENDENCIES[name]['install_guide']}")
            return False

        logger.info("✅ 所有环境依赖检查通过", 2)
        return True


if __name__ == "__main__":
    checker = EnvironmentChecker()
    if not checker.check_environment():
        sys.exit(1)
